/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package edu.pdx.cs.guavalib;

import edu.pdx.cs.guavadata.AppData;
import edu.pdx.cs.guavadata.Guava;
import edu.pdx.cs.guavadata.data.DMLType;
import edu.pdx.cs.guavadata.domain.Domain;
import edu.pdx.cs.guavadata.domain.UniqueIdentifier;
import edu.pdx.cs.guavadata.subclass.ControlType;
import edu.pdx.cs.guavadata.subclass.DataColumn;
import edu.pdx.cs.guavadata.subclass.DataTable;
import edu.pdx.cs.guavadata.subclass.GuavaForm;
import edu.pdx.cs.guavadata.subclass.LaunchType;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import javax.swing.JLabel;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableModel;

/**
 *
 * @author VuTran
 */
public class GJTable extends JTable implements Guava {
    private DataTable dv;
    private DataTable dsTable;
    private UUID gid;
    private String gname;
    private JLabel label;
    private DefaultTableModel tableModel;
    private String cellValue = "";
    private Map<Integer, Integer> rowMapping = null;

    public GJTable() {
        super();
        this.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
        this.setRowSelectionAllowed(true);
        rowMapping = new HashMap<Integer, Integer>();

        addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                onKeyPress(e);
            }

        });
    }

    public void onKeyPress(KeyEvent e) {
       
        if (e.getKeyCode() == KeyEvent.VK_DELETE) {
            int[] selectedRow = this.getSelectedRows();
            clearSelection();
            for (int i = selectedRow.length - 1; i >= 0; i--) {
                Map<String, Object> rowInDataView = dv.rows.get(rowMapping.get(selectedRow[i]));
                if (rowInDataView.get(DataTable.ROW_STATE).equals(DataTable.ROW_NORMAL)) {
                    rowInDataView.put(DataTable.ROW_STATE, DataTable.ROW_DELETE);
                } else if (rowInDataView.get(DataTable.ROW_STATE).equals(DataTable.ROW_INSERT)) {
                    rowInDataView.put(DataTable.ROW_STATE, DataTable.ROW_INSERT_DELETE);
                }
                // remapping
                for (int j = selectedRow[i]; j < this.getRowCount() - 1; j++) {
                    rowMapping.put(j, rowMapping.get(j + 1));
                }
                tableModel.removeRow(selectedRow[i]);
                //AppData.deleteRow(getGName(), UUID.fromString(dv.rows.get(i).get("id").toString()));
               // dv.setRowState(i, DataTable.ROW_DELETE);
                //dv.rows.remove(selectedRow[i]);
                //dsTable.rows.remove(selectedRow[i]);
            }
        } else if (e.getKeyCode() == KeyEvent.VK_ENTER || e.getKeyCode() == KeyEvent.VK_TAB) {
            int row = this.getSelectedRow();
            int rowMap = rowMapping.get(row);
            Map<String, Object> rowInDataView = dv.rows.get(rowMapping.get(row));
            if (rowInDataView.get(DataTable.ROW_STATE).equals(DataTable.ROW_NORMAL)) {
                rowInDataView.put(DataTable.ROW_STATE, DataTable.ROW_UPDATE);
            }

//            int column = this.getSelectedColumn();
//            dv.rows.get(row).put(getModel().getColumnName(column), cellValue);
//            dsTable.rows.get(row).put(getModel().getColumnName(column), cellValue);
//            AppData.commitRow(getGName(), UUID.fromString(dv.rows.get(row).get("id").toString()), DMLType.UPDATE);
//            System.out.println("restart");
//            cellValue = "";


            if (this.getRowCount() == row + 1) {
                tableModel.addRow(new Object[] {});
                addNewRow();
                rowMapping.put(row + 1, dv.rows.size() - 1);
                //AppData.commitRow(getGName(), UUID.fromString(newRow.get("id").toString()), DMLType.INSERT);
            }
        }
//        } else if (e.getKeyCode() == KeyEvent.VK_BACK_SPACE) {
//            if (cellValue.length() > 1)
//                cellValue = cellValue.substring(0, cellValue.length() - 1);
//            System.out.println(cellValue);
//        } else {
//            cellValue += e.getKeyChar();
//            System.out.println(cellValue);
//        }

    }


    public JLabel getLabel() {
        return label;
    }

    public void setLabel(JLabel label) {
        this.label = label;
    }

    public DataTable getDataView() {
        return dv;
    }

    public void setDataView(DataTable dt) {
        dv = dt;
    }

    public LaunchType getLType() {
        return LaunchType.NA;
    }

    public ControlType getCType() {
        return ControlType.Entity;
    }

    public String getGText() {
        if (this.label == null)
            return null;
        return this.label.getText();
    }

    public String getGName() {
        if (gname == null)
            return this.getName();
        return gname;
    }

    public void setGName(String GName) {
        gname = GName;
    }

    public Point getGLocation() {
        return this.getLocation();
    }

    public Dimension getGSize() {
        return this.getSize();
    }

    public List<Guava> getGComponents() {
        convertColumnToGuavaComponent();
        List<Guava> lg = new ArrayList<Guava>();
        GTableColumnModel colModel = (GTableColumnModel) this.getColumnModel();
        for (int i = 0; i < colModel.getGColumnCount(); i++) {
           lg.add((Guava) colModel.getGColumn(i));
        }
        return lg;
    }

    public void gBind(String table, int e) {
        gid = ((GuavaForm) this.getTopLevelAncestor()).getID();
        //AppData.deleteRow(getGName(), UUID.fromString(dv.rows.get(dv.rows.size() - 1).get("id").toString()));
        dv.rows.get(dv.rows.size() - 1).put(DataTable.ROW_STATE, DataTable.ROW_INSERT_DELETE);

        for (Map<String, Object> row : dv.rows) {
            if (row.get(DataTable.ROW_STATE).equals(DataTable.ROW_DELETE)) {
                AppData.deleteRow(getGName(), UUID.fromString(row.get("id").toString()));
            }
        }

        for (int i = 0; i < this.tableModel.getRowCount(); i++) {
            Map<String, Object> rowInDataView = dv.rows.get(rowMapping.get(i));
            if (rowInDataView.get(DataTable.ROW_STATE).equals(DataTable.ROW_INSERT)
                    || rowInDataView.get(DataTable.ROW_STATE).equals(DataTable.ROW_UPDATE)) {
                // get corresponding row in AppData
                Map<String, Object> rowInAppData = null;
                for (int j = 0; j < dsTable.rows.size(); j++) {
                    if (rowInDataView.get("id").toString().equalsIgnoreCase(dsTable.rows.get(j).get("id").toString())) {
                        rowInAppData = dsTable.rows.get(j);
                        break;
                    }
                }

                // update from table
                for (int j = 0; j < tableModel.getColumnCount(); j++) {
                    rowInAppData.put(this.getColumnName(j), this.getValueAt(i, j));
                }

                if (rowInDataView.get(DataTable.ROW_STATE).equals(DataTable.ROW_INSERT)) {
                    AppData.commitRow(getGName(), UUID.fromString(rowInAppData.get("id").toString()), DMLType.INSERT);
                } else {
                    AppData.commitRow(getGName(), UUID.fromString(rowInAppData.get("id").toString()), DMLType.UPDATE);
                }
            }
        }
    }

    public void gBindFromDatabase(String table, int e) {
        gid = ((GuavaForm) this.getTopLevelAncestor()).getID();

        AppData.fetchRowsByFK(getGName(), gid);
        dsTable = AppData.ds.getTable(getGName());

        // Create a view of the destination table that only has the current ID's
        if (!(gid.equals(UUID.nameUUIDFromBytes("000".getBytes())))) {
            // dv = new DataView(targetTable, "fk='" + gid.ToString() + "'", firstColumn, DataViewRowState.CurrentRows);
            dv = dsTable.getDataView("fk", gid.toString());
        } else {
            dv = dsTable.getDataView("fk", "%");
        }

        buildTable();
    }

    public void buildTable() {
        tableModel = (DefaultTableModel) this.getModel();
        int rowCount = 0;
        for (Map<String, Object> row : dv.rows) {
            row.put(DataTable.ROW_STATE, DataTable.ROW_NORMAL);
            Object[] rowObj = new Object[row.size() - 2];
            //int i = 0;
            //for (Object col : row.keySet()) {
            for (int i = 0; i < this.getColumnCount(); i++) {
                String col = this.getColumnName(i);
                if (!col.toString().equals("id") && !col.toString().equals("fk")
                        && !col.toString().equals(DataTable.ROW_STATE)) {
                    rowObj[i] = row.get(col);
                }
            }
            tableModel.addRow(rowObj);
            rowMapping.put(rowCount, rowCount);
            rowCount++;
        }
        tableModel.addRow(new Object[]{});
        addNewRow();
        rowMapping.put(tableModel.getRowCount() - 1, dv.rows.size() - 1);
        //AppData.commitRow(getGName(), UUID.fromString(newRow.get("id").toString()), DMLType.INSERT);
        
        repaint();
    }

    public String getGDefault() {
        return null;
    }

    public String getGToolTip() {
        return this.getToolTipText();
    }

    public Domain getGDomain() {
        return new UniqueIdentifier();
    }

    public Guava get(String s) {
        for (Guava g : this.getGComponents()) {
            if (g.getGName().equals(s)) {
                return g;
            }
        }
        return null;
    }

    private void convertColumnToGuavaComponent() {
        TableColumnModel colModel = this.getColumnModel();
        GTableColumnModel newColModel = new GTableColumnModel();
        for (int i = 0; i < colModel.getColumnCount(); i++) {
            TableColumn oldColumn = colModel.getColumn(i);
            GTableColumn newColumn = new GTableColumn(oldColumn, this.getColumnName(i));
            newColModel.addGColumn(newColumn);
        }
        this.setColumnModel(newColModel);
    }

    public Map<String, Object> addNewRow() {
        Map<String, Object> newRow = new HashMap<String, Object>();
        Map<String, Object> newRowDv = new HashMap<String, Object>();
        UUID id = UUID.randomUUID();
        newRow.put("id", id);
        newRowDv.put("id", id);
        newRow.put("fk", ((GuavaForm) this.getTopLevelAncestor()).getID());
        newRowDv.put("fk", ((GuavaForm) this.getTopLevelAncestor()).getID());
        for (DataColumn col : dv.columns) {
            if (!col.getName().equals("id") && !col.getName().equals("fk")) {
                newRow.put(col.getName(), "");
                newRowDv.put(col.getName(), "");
            }
        }
        newRowDv.put(DataTable.ROW_STATE, DataTable.ROW_INSERT);
        dv.rows.add(newRowDv);
        dsTable.rows.add(newRow);
       
        return newRowDv;
    }

    /**
     * @return the cellValue
     */
    public String getCellValue() {
        return cellValue;
    }

    /**
     * @param cellValue the cellValue to set
     */
    public void setCellValue(String cellValue) {
        this.cellValue = cellValue;
    }

}
